一篇好文,助你上手 Glide
版权声明:
本公众号发布的所有文章,未特殊署名,均属于原创,版权归本公众号所有。
转载请参阅公众号的:《转载授权》。
一、前言
Glide 现在大范围的使用在各种商业项目中,而对于一般而言, Glide 的 Api 封装的非常好,多数情况下我们只需要使用它,在使用的基础之上,才考虑如何了解它。
本文的目的是让你如何快速上手 Glide 3.x ,来快速投入开发,本文力求做到快速上手,所以只讲在上手的时候,你需要关注的。
本文最开始只是想做一个简短的快速上手的教程,但是在写的过程中,越写越长。但是内容都是我觉得必须要讲清楚的,所以如果想要快速上手 Glide,请耐心阅读。
二、简单使用
2.1 什么是 Glide ?
既然要用到 Glide ,那就先简单的介绍一下 Glide 。
Glide 简单来说就是一个 Google 主导的图片加载开源库。它稳定、速度快、可自适应图片尺寸、支持众多格式、支持加载不同来源的图片、内存和磁盘缓存的优化。这些,都是它的好处(当然不止这些),这里就不一一细说了。
你只需要知道,它是一款主流的图片加载库即可,它包含了你能想到的所有功能,并且支持扩展。
Glide 的 Github 地址:
https://github.com/bumptech/glide
2.2 在项目内集成 Glide
虽然它已经到 v4.x 了,但是本文还是就最常用的 v3.8.0 版本的集成,做一个简单的介绍。
集成的方式有多种,可以直接引用 jar 包,也可以使用 Maven,这里还是使用主流的 Gradle 来集成它。
如果需要配置混淆,还需要在混淆文件中区分 Glide 。
Glide 只是一个图片加载库,而大多数情况下,我们的图片均来自互联网。所以它的网络请求库,其实是可以配置的,Glide 可以支持 OkHttp 和 Volley 。
这里使用的另外一个优秀的网络请求库 OkHttp 来做支持。
配好 Glide ,我们就可以开始使用它了。
2.3 最简单的使用
Glide 是支持链式调用的,但是它不是简单的在每个方法中,返回 this ,它更复杂一些,后面会讲到,所以通常使用它只需要使用一条语句即可。
这是一个最简单的 Glide 的 Demo,使用它即可从网络上加载一张图片到一个 ImageView 中去显示。
三、Glide 需要了解的内容
前面的例子可以看到,实际上 Glide 的链式调用,它的主要方法就是三个,先来简单看看他们.
with : 主要是传递一个 Glide 可用的 Context,它和生命周期相关。
load:接收一个待加载的图片资源,可支持多种格式。
into;指定加载的图片的最终使用目标对象,例如可以是一个 ImageView。
这三个主要的部分,贯穿了 Glide 使用的主要重点内容,接下来让我们好好看看他们。
3.1 with()
前面提到,这里的 with()
方法用于给 Glide 传递一个 Context 对象,它可以支持多种 Context。
对于 with 而言,它会返回一个 RequestManager 用于管理请求,而它接收的这些不同的 Context ,并不是为了让我们方便使用,而是会对当前 Context 的生命周期做监听,来管理 Glide 自身的图片加载的请求。
举个例子:当使用 with(Activity
) 的时候,如果此时当前 Activity 被关闭掉了,那么 Glide 就会将这个 Activity 下所有的图片请求停止掉。也就是实现了 Glide 和 页面声明周期的绑定,来优化 Glide 自身的请求策略。
所以,在使用 Glide 的时候,尽量使用当前页面的 Activity ,而非直接传递一个 Context 进去。尽量小的选择 Context 的范围,他们的推荐优先级为:
Fragment > Activity > Context
3.2 load()
load()
方法,就是去指定一个待加载的资源,它支持很多格式和资源种类。例如:网络地址、本地文件、Drawable 等,它都是可以做到很好的加载的。
load()
方法,并不是在 Glide 中,前面也提到 with()
会返回一个 RequestManager 对象,load()
方法在它内部实现。
具体 load()
方法,支持的资源种类,可以看到它方法的重载,基本上我们能想到的,它都支持。
有意思的是 load()
方法,它返回的是另外一个 DrawableTypeRequest 对象。
3.3 into()
into()
方法,用于指定加载的图片资源,最终给谁来使用。这个没什么好说的,加载的图片,最终一定是用来显示的,所以它需要指定一个使用图片的对象。
into()
实际上是 DrawableTypeRequest 中的方法,DrawableTypeRequest 是一个多层继承的类,它实际上自己是没有对 into()
方法的实现的,大部分实现都是在其父类 DrawableRequestBuilder 和 父类的父类 GenericRequestBuilder 中的,但是这并不影响我们使用它。
从方法的签名,可以看到 into()
不只是可以接受一个 ImageView ,也可以是一些其他的什么。这也很好理解,在项目内,也不仅仅只有 ImageView 可以用来显示图片,View 的 background 也是可以用于显示图片的。
除了 ImageView 前面已经介绍过了,直接使用即可。剩下的后面会有讲到。
四、Glide 的使用细节
既然 Glide 使用过程中,最重要的三个方法已经介绍过了,他们是 Glide 能完成功能的基础,接下来,就开始介绍 Glide 的使用细节,来见证 Glide 的强大。
本节介绍的 Glide 的使用细节,基本上都是与 load()
方法返回的 DrawableTypeRequest 对象进行操作,对其进行一些配置。
4.1 不同状态的占位图
在图片加载的过程中,会经历过多过程,例如:加载中、加载失败等等,在这些过程中,其实是可以为暂时为 ImageView 设置一个占位的的,来定制加载中、加载失败这种状态的显示效果。
Glide 定制的占位图,有三种:
placeholder :指定加载前显示的图片资源。
error:指定加载失败显示的图片资源。
fallback:指定传递加载资源为 null 的时候,显示的图片资源。
例如上面的例子中,其实 fallback()
是无需指定的,因为 imageUri 是不可能为 null 的。而其他的,都会在不同的阶段显示出来,加载前会显示 load_placeholder ,如果加载失败了,会显示 load_error 。
注意,不同状态的占位图,实际上是一种容错的表现,所以只能用于加载一个『本地资源』,允许传递一个 @DrawableId 或者 Drawable 对象。
4.2 缩放控制
某些时候,因为图片的尺寸和控件的尺寸,不一定能匹配,所以会对图片的显示效果,进行一些缩放,而大多数情况下,这种默认的缩放策略,并不是我们想要的。
Glide 提供了一些方法来控制缩放的效果。
centerCrop()
fitCenter()
这两个方法和 ImageView.setScaleType() 中传递的参数效果类似,就不再一一赘述了。
4.3 缓存控制
现在基本上所有的图片加载库,都是遵照三级缓存的策略:网络、磁盘、内存。Glide 也是如此,并且默认情况下,为了更好的体验,这些缓存都是全部开启的。
就 Glide 的缓存策略而言,其实我们也是有办法去调整的。
对于内存缓存而言,只有有或者没有的情况,所以 Glide 只提供了一个 skipMemoryCache()
方法,它可以传递一个 Boolean 的值,用于指定是否跳过磁盘缓存,默认情况下是 false ,表示需要内存缓存。
但是对于磁盘缓存,就会更复杂一些。Glide 为了保证效率,实际上默认情况下是会去缓存多种尺寸的图片在磁盘上的,也就是说,对于同一个 Uri,如果你在不同尺寸的 ImageView 中使用到它了,默认情况下,在你设备的磁盘上,也会有多张不同尺寸的图片。这样是为了下次加载的时候,速度更快,无需再对原图进行处理,是一种以空间换效率的策略。
而如果我们需要对磁盘缓存进行调节,就需要使用 diskCacheStrategy()
方法来改变它,前面提到它是一种比较复杂的策略,所以无法简单的使用一个 Boolean 值就完成了。它需要传递一个 DiskCacheStrategy 的枚举类型。
可以看到,它实际上是通过两个参数来标记磁盘缓存的策略的。
ALL:缓存所有类型的图片(默认行为)。
NONE :禁用磁盘缓存。
SOURCE : 只缓存全尺寸的原图。
RESULT :只缓存压缩后的图片。
所以具体使用那种,就需要看当前加载的图片属于哪一种了。
上面的例子就是忽略内存缓存,并且磁盘只缓存原图的策略。
4.4 加载优先级
对于同一个页面,如果需要在多个地方都加载线上图片,必然会存在一个优先级的问题。例如:正常来说,背景图是比其他图片优先级更高的图片。
Glide 是可以在加载中,对当前加载的图片,调整加载的优先级的。需要使用 priority()
方法,它可以接受一个 Priority 的枚举类型,包含四种值:LOW(低)、HIGH(高)、NORMAL(普通)、IMMEDIATE(立即)。
可以在我们需要的时候,对其进行配置,但是它并不影响用 Glide 加载的图片的显示顺序,只是用于 Glide 在加载图片的时候一个优化请求的参数而已,并不影响最终显示的顺序。
4.5 载入动画
Glide 在显示图片的时候,为了让显示效果不那么突兀,会以一种更柔和的方式去显示,就会在加载的时候给一个动画效果,它可以使用 crossFade()
方法进行配置,如果不特殊处理,默认它是开启的,并且本身默认动画的时长是 300ms。
crossFade()
也是有多个重载的,主要是为了指定动画以及动画的时长。如果有心,也可以看看 crossFade()
的源码,它实际上只是对 animate()
方法的一个包装而已,后面会讲到。
而 crossFade()
的效果是默认开启的,所以如果我们不需要这样的一个动画效果,可以使用 dontAnimate()
来禁用动画效果。
有一些情况下,crossFade()
方法并不能满足我们的需求。如果对加载的动画有特殊的定制需要,可以使用更灵活的 animate()
方法来自己实现动画。
可以看到,animate()
支持多种格式的动画的配置,对于动画的效果,这里就不一一讲解了。
4.6 支持 Gif & 视频
Glide 的一个非常棒的功能,就是可以支持 Gif,并且使用起来和正常的想要加载一张网络上的图片,并没有什么区别。
上面的例子中,会在 mBgImageView 中显示 Gif 图的效果,并且自动播放,并且可以在加载前为其设置一个占位图,这些都和加载一个普通的图片没有什么区别。
但是有时候我们需要对加载的 Gif 图做一个检查,例如校验它是否是一个 Gif ,如果不是,则认为是一次错误的加载。这个时候就可以使用 asGif()
来进行校验,如果当前加载的图片不是一个正确的 Gif 格式,则会去显示 error()
配置的图片。
当然,有时候我们可能只是为了显示一张图片,可以强制显示 Gif 图片的第一帧,使用 asBitmap()
方法标记即可。
只需要将 asGif()
替换成 asBitmap()
就饿可以了,这里不再单独提供示例了。
Glide 对 Gif 的支持之外,提示还对 Video 格式的文件也进行了支持。但是它和 Gif 显示的效果不一样的一点在于,它并不会去播放视频文件,而只是将视频文件的第一帧做为一个图片去显示出来。如果依然想要播放一段视频文件,使用 Glide 不是一个好注意,你应该使用 VideoView。
其次 Glide 对视频的支持,仅限于本地视频, 47 32250 47 15290 0 0 2353 0 0:00:13 0:00:06 0:00:07 2875 47 32250 47 15290 0 0 2038 0 0:00:15 0:00:07 0:00:08 2912 47 32250 47 15290 0 0 1798 0 0:00:17 0:00:08 0:00:09 2916并无法对网络视频进行支持。
4.7 加载监听
如果有对 Glide 加载的图片的结果进行监听的,可以使用 listener()
方法设置一个监听器,它接收一个 RequestListener 的接口
一般而言,如果我们需要监听图片加载错误的原因,可以在 onException()
中做处理。
需要注意的是,这两个方法的返回值,最好都是 false,因为如果返回 true ,将表示你已经处理了这次的事件,而 Glide 将不会再做额外的处理。例如,如果 onException()
返回了 true 的话,在图片加载失败之后,error()
中设置的图片,并不会被显示,因为 Glide 认为开发者已经在外部对这个错误进行了处理。
4.8 变换加载的图片
对于使用 Glide 加载的图片,如果想要在其显示之前,对其进行一些变换操作,例如,改变颜色、虚化、圆角子类的,都需要用到 transfrom()
方法,它主要用于支持在图片显示之前,自定义的变换效果。
变换有两个方法:
transfrom():它可以添加一个通用的变换效果。
bitmapTransfrom():限制了变换的类型,只能设置 Bitmap 的变换。
变换这种操作,其实定制性非常的强,展开讲就比较复杂了,大家只需要知道,Glide 是可以对加载的图片在显示之前进行一些预处理的操作的,在具体使用的时候再回头来看相关资料即可。
这里推荐一个开源的库,来支持大多数变换的效果。
Github 地址:
https://github.com/wasabeef/glide-transformations
4.9 into() 其他实现
前面所有的例子中,into()
方法作为 Glide 加载图片流程的最后一个环节,它不仅仅只能支持一个 ImageView。有时候我们还需要给 View 中设置一个背景的需要,这个使用 Glide 也是可以办到的,但是就需要用到 into()
方法的其他重载方法了。
撇开 into(ImageView) 不说,into(int,int) 实际上是一个指定尺寸的同步方法,可以在子线程中,通过它来得到一个 GlideDrawable 对象。
但是这并不是很常用的场景,大部分我们还是使用泛型的方式来使用 Glide 的。
它的完整签名可以看出,它实际上接收的是一个 Target 对象,而 Glide 同时也提供了非常多的 Target 的子类。
这些子类里面,有一些是不常用的,例如 AppWidgetTarget 和 NotificationTarget 就是为了 AppWidget 和 Notification 中加载图片准备的。这里只介绍两个比较常用的 Target :SimpleTarget 和 ViewTarget ,其实使用起来都是大同小异。
如果我们不关心图片加载的用途,只是单纯的需要加载一个 Bitmap 或者 Drawable ,就可以使用 SimpleTarget 来处理。
SimpleTarget 可以接受一个 GlideDrawable 或者 Bitmap 的类型作为加载的类型。如果需要指定加载的图片尺寸,还可以在构造方法中指定,如果不对其进行指定,则加载的是图片的原尺寸。
再来看看 ViewTarget, 从名称上可以才出来,它实际上是想让 Glide 加载一个图片资源给某个 View 使用。它可以解决有时候我们显示图片的 View 并不是一个 ImageView 的问题,也可能是一个 View 的背景。
ViewTarget 需要指定 View 的类型,以及加载的资源类型,这里直接使用的 View 和 GlideDrawable ,然后将我们需要的使用图片的目标 View 当构造参数传递进去即可,最终它它会一个内部 view 变量去持有它,供之后使用。
在 onResourceReady() 这个回调方法中,直接按我们的需要使用 GlideDrawable 和 View 即可。
如果是需要在非 ImageView 的其他 View 上使用图片,推荐使用 ViewTarget 。它内部是会去计算 View 的尺寸,来优化缓存的图片。和加载 ImageView 的效果是一样的,如果使用 SimpleTarget 就需要考虑到 View 的尺寸问题了。
在使用 Target 的时候,还有一点需要额外注意的。
前面也提到,Glide 此次加载的图片生命周期,会和 with() 传递进去的 Context 的生命周期进行绑定,所以使用 Target 加载图片的时候,就需要额外注意了,如果不是和页面绑定的图片资源,可以使用 ApplicationContext() ,避免当前页面被销毁之后,加载的请求也被停止了。
五、小结
本文最开始只是想要做一个适合初学者快速上手的 Glide 使用手册,但是越写越长,读到这里相信你也能有所收获,之后如果觉得有写概念也需要初学者了解,会继续补充。
推荐阅读: